<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>14-3D看房</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    html,
    body {
      width: 100%;
      height: 100%;
    }
    .tools {
      width: 100%;
      position: absolute;
      top: 0;
      left: 0;
      z-index: 2;
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 4px 10px;
      box-sizing: border-box;
    }
    .tips {
      position: absolute;
      top: 0;
      left: 0;
      z-index: -1;
      font-size: 14px;
      opacity: 0;
      transition: opacity 0.3s;
    }
  </style>
</head>

<body>
  <p class="tips">进入</p>
  <script type="module">
    import * as THREE from "three";
    import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
    import { Timer } from "three/addons/misc/Timer";
    // 创建场景
    const scene = new THREE.Scene();
    // 创建相机
    const camera = new THREE.PerspectiveCamera(
      75,
      window.innerWidth / window.innerHeight,
      0.1,
      1000
    );
    camera.position.set(0, 0, 30);
    scene.add(camera);
    // 创建渲染器 
    const renderer = new THREE.WebGLRenderer({
      antialias: true
    });
    // 设置渲染器大小
    renderer.setSize(window.innerWidth, window.innerHeight);
    // 把渲染的canvas内容添加到body
    document.body.appendChild(renderer.domElement);

    // 立方体看房
    // // 贴图加载器
    // const textureLoader = new THREE.TextureLoader();
    // const imgs = [
    //   "../images/3dhouse/scene_left.jpeg",
    //   "../images/3dhouse/scene_right.jpeg",
    //   "../images/3dhouse/scene_top.jpeg",
    //   "../images/3dhouse/scene_bottom.jpeg",
    //   "../images/3dhouse/scene_front.jpeg",
    //   "../images/3dhouse/scene_back.jpeg"
    // ]
    // const materials = [];
    // imgs.forEach(url => {
    //   let texture = textureLoader.load(url);
    //   let material = new THREE.MeshBasicMaterial({ map: texture });
    //   materials.push(material);
    // })
    // // 创建立方体盒子
    // const cube = new THREE.Mesh(
    //   new THREE.BoxGeometry(40, 40, 40),
    //   materials
    // );
    // // z轴负值，可以把摄像机视角反转。变成从里向外看
    // cube.geometry.scale(12, 12, -12);
    // scene.add(cube);

    // 球体看房
    // 用于简单模拟3个坐标轴的对象
    // 红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴
    // const axesHelper = new THREE.AxesHelper(20);
    // scene.add(axesHelper);

    const texture = new THREE.TextureLoader().load("../images/3dhouse/livingRoom.jpg");
    const sphereGeometry = new THREE.SphereGeometry(16, 32, 32);
    const sphereMaterial = new THREE.MeshBasicMaterial({ map: texture });
    const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
    sphere.geometry.scale(12, 12, -12);
    scene.add(sphere);

    // 点精灵
    const spriteTexture = new THREE.TextureLoader().load("../images/3dhouse/kitchen.png");
    const spriteMaterial = new THREE.SpriteMaterial({ map: spriteTexture });
    const sprite = new THREE.Sprite(spriteMaterial); 
    sprite.scale.set(20, 10, 1);
    sprite.position.set(-110, -10, -80);
    scene.add(sprite);

    // 光线投射
    const raycaster = new THREE.Raycaster();
    const poiner = new THREE.Vector2();

    // 提示框元素
    const oTips = document.querySelector(".tips");
    renderer.domElement.addEventListener("mousemove", (e) => {
      // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
      // 需要将世界坐标进行归一化变成设备坐标
      poiner.x = (e.clientX / window.innerWidth) * 2 - 1;
      poiner.y = -(e.clientY / window.innerHeight) * 2 + 1;
      raycaster.setFromCamera(poiner, camera);
      const intersect = raycaster.intersectObject(sprite);

      if(intersect.length) {
        const object = intersect[0].object;
        object.material.color.set(0x00ff00);
        
        const worldVector = new THREE.Vector3(
          intersect[0].object.position.x,
          intersect[0].object.position.y,
          intersect[0].object.position.z
        );

        // 最后把设备坐标转换成屏幕坐标
        // start
        const dncPosition = worldVector.project(camera);
        const halfw = window.innerWidth / 2;
        const halfH = window.innerHeight / 2;
        let left = halfw * dncPosition.x + halfw;
        let top = -halfH * dncPosition.y + halfH
        // end
        left = left - oTips.clientWidth / 2;
        top = top - oTips.clientHeight / 2 - 30;
        oTips.style.left = left + "px";
        oTips.style.top = top + "px";
        oTips.style.zIndex = 2;
        oTips.style.opacity = 1;
      } else {
        sprite.material.color.set(0xffffff);
        oTips.style.left = 0;
        oTips.style.top = 0;
        oTips.style.zIndex = -1;
        oTips.style.opacity = 0;
      }
    });
    let roomType = "room";
    renderer.domElement.addEventListener("mousedown", (e) => {
      poiner.x = (e.clientX / window.innerWidth) * 2 - 1;
      poiner.y = -(e.clientY / window.innerHeight) * 2 + 1;
      raycaster.setFromCamera(poiner, camera);
      const intersect = raycaster.intersectObject(sprite);
      let changeTextureURL = ""; 
      let changeSpriteTextureURL = "";
      if (intersect.length) {
        if(roomType === "room") {
          changeTextureURL = "../images/3dhouse/kitchen.jpg";
          changeSpriteTextureURL = "../images/3dhouse/room.png";
          roomType = "kitchen";
        } else {
          changeTextureURL = "../images/3dhouse/livingRoom.jpg";
          changeSpriteTextureURL = "../images/3dhouse/kitchen.png";
          roomType = "room";
        }
        // 更改球体贴图
        const changeTexture = new THREE.TextureLoader().load(changeTextureURL);
        const changeMaterial = new THREE.MeshBasicMaterial({ map: changeTexture });
        sphere.material = changeMaterial;

        // 更改点精灵贴图
        const changeSpriteTexture = new THREE.TextureLoader().load(changeSpriteTextureURL);
        const changeSpriteMaterial = new THREE.SpriteMaterial({ map: changeSpriteTexture });
        sprite.material = changeSpriteMaterial;
        roomType === "kitchen" ? sprite.position.set(-100, -10, 80) : sprite.position.set(-110, -10, -80);
      }
    });

    // 创建轨道控制器
    const controls = new OrbitControls(camera, renderer.domElement);

    // 方便摆放模型位置
    // controls.addEventListener("change", () => {
    //   console.log(camera.position);
    // })

    // 开启物体的阻尼动画效果 
    controls.enableDamping = true;

    

    // 监听controls的change事件
    controls.addEventListener("change", () => {
      // 交互的鼠标每次发生变化，都需要渲染一次(如果用了animate函数就不需要).
      renderer.render(scene, camera);
    });
    renderer.render(scene, camera);

    // 此类是 Clock 的替代品，具有不同的 API 设计和行为。目标是避免随着时间的推移 Clock 中变得明显的概念缺陷。
    const timer = new Timer();
    function animate(timestamp) {
      requestAnimationFrame(animate);
      timer.update(timestamp);
      const delta = timer.getDelta();
      controls.update();
      renderer.render(scene, camera);
    } 
    
    // 添加动画并渲染
    animate();
  </script>
</body>

</html>